package cc.rengu.igas.cops.core.service.trans.payment;

import cc.rengu.igas.cops.common.enums.RespCodeEnum;
import cc.rengu.igas.cops.core.service.base.ManageService;
import cc.rengu.igas.cops.facade.request.ModifyPayPasswdRequest;
import cc.rengu.igas.cops.facade.response.ModifyPayPasswdResponse;
import cc.rengu.igas.share.common.constant.UserSessionConstant;
import cc.rengu.igas.share.common.enums.SignTypeEnum;
import cc.rengu.igas.share.core.model.UserInfo;
import cc.rengu.igas.share.core.realize.UserService;
import cc.rengu.igas.share.core.realize.impl.UserServiceImpl;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.NonFinanceTxnMapper;
import cc.rengu.oltp.service.common.dao.SignAcctInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.NonFinanceTxnMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SignAcctInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.NonFinanceTxn;
import cc.rengu.oltp.service.common.entity.SignAcctInfo;
import cc.rengu.oltp.service.common.enums.PinTypeEnum;
import cc.rengu.oltp.service.common.enums.SmsTypeEnum;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.PasswordInfo;
import cc.rengu.oltp.service.realize.ImageCodeService;
import cc.rengu.oltp.service.realize.SafeKeyBoardService;
import cc.rengu.oltp.service.realize.SmsService;
import cc.rengu.oltp.service.realize.impl.ImageCodeServiceImpl;
import cc.rengu.oltp.service.realize.impl.SafeKeyBoardServiceImpl;
import cc.rengu.oltp.service.realize.impl.SmsServiceImpl;
import cc.rengu.oltp.utility.util.ConvertUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;

import java.util.List;
import java.util.stream.Collectors;

public class CopsModifyPayPasswdService extends ManageService {

    @Override
    protected Object bizBeforeCust() throws Exception {
        ModifyPayPasswdRequest modifyPayPasswdRequest = new ModifyPayPasswdRequest();
        ConvertUtil.convertOutput(modifyPayPasswdRequest);
        return modifyPayPasswdRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        BizResponse<ModifyPayPasswdResponse> bizResponse = new BizResponse<>();
        ModifyPayPasswdResponse modifyPayPasswdResponse = new ModifyPayPasswdResponse();
        bizResponse.setRspSysId(AppParamConstant.SYS_ID);
        ModifyPayPasswdRequest modifyPayPasswdRequest = (ModifyPayPasswdRequest) request;
        String instId = modifyPayPasswdRequest.getHeader().getInstId();
        String userId = modifyPayPasswdRequest.getUserId();
        String txnMode = modifyPayPasswdRequest.getTxnMode();
        String password = modifyPayPasswdRequest.getPassword();

        //获取会话信息
        UserService userService = new UserServiceImpl();
        UserInfo userInfo = userService.getUserInfo(instId, userId, modifyPayPasswdRequest.getHeader().getSession());
        if (null == userInfo) {
            rglog.error("获取用户信息失败!");
            throw new BizException(RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespCode(), RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespDesc());
        }
        // 获取用户签约主体及签约类型
        String signInst = userService.getUserSignInst();
        String signType = (null == platMchntInfo) ? SignTypeEnum.BANK_CLASS_SIGN.getSignTypeCode() : platMchntInfo.getSignType();
        //交易类别 00-身份验证
        if ("00".equals(txnMode)) {
            String authMode = modifyPayPasswdRequest.getCustAuthInfo().getAuthMode();
            switch (authMode) {
                //手机号+支付密码
                case "00": {
                    String phoneNo = modifyPayPasswdRequest.getCustAuthInfo().getPhoneNo();
                    //校验手机号
                    if (!userInfo.getMobileNo().equals(phoneNo)) {
                        rglog.info("用户信息不匹配");
                        throw new BizException(RespCodeEnum.USER_INFO_MISMATCH.getRespCode(), RespCodeEnum.USER_INFO_MISMATCH.getRespDesc());
                    }
                    //校验支付密码
                    boolean checkResult = userService.checkUserPayPassword(instId, modifyPayPasswdRequest.getUserId(), null, modifyPayPasswdRequest.getPassword());
                    if (!checkResult) {
                        rglog.error("用户密码错误!");
                        throw new BizException(RespCodeEnum.USER_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_PASSWORD_ERROR.getRespDesc());
                    }
                    //查询短信验证码表（T_P_SMS_INFO），校验短信验证码
                    String smsCode = modifyPayPasswdRequest.getCustAuthInfo().getSmsCode();
                    String smsVerifySeqNum = modifyPayPasswdRequest.getCustAuthInfo().getSmsVerifySeqNum();
                    SmsService smsService = new SmsServiceImpl();
                    smsService.verifySmsCode(instId, SmsTypeEnum.MODIFY_PASSWORD.getSmsType(), smsCode, smsVerifySeqNum);
                    break;
                }
                //银行卡+支付密码
                case "01": {
                    //校验图形验证码
                    ImageCodeService imageCodeService = new ImageCodeServiceImpl();
                    boolean imageVerifyFlag = imageCodeService.verifyImageCode(instId, modifyPayPasswdRequest.getCustAuthInfo().getImageAuthCode(), userService.getUserSessionValue("imageAuthCode"));
                    if (!imageVerifyFlag) {
                        rglog.error("图片验证码校验失败!");
                        throw new BizException(RespCodeEnum.VERIFICATION_CODE_INVALID.getRespCode(), RespCodeEnum.VERIFICATION_CODE_INVALID.getRespDesc());
                    }
                    //校验支付密码
                    boolean checkResult = userService.checkUserPayPassword(instId, modifyPayPasswdRequest.getUserId(), null, modifyPayPasswdRequest.getPassword());
                    if (!checkResult) {
                        rglog.error("用户密码错误!");
                        throw new BizException(RespCodeEnum.USER_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_PASSWORD_ERROR.getRespDesc());
                    }
                    //银行卡号字段（payAcctNo）查询签约信息表，验证证件号码字段
                    SignAcctInfoMapper signAcctInfoMapper = new SignAcctInfoMapperImpl();
                    List<SignAcctInfo> signAcctInfos = signAcctInfoMapper.selectSignAcctInfoBySignTyUserId(instId, userId, signInst);
                    if (signAcctInfos == null || signAcctInfos.isEmpty()) {
                        rglog.info("签约关系不存在，instId:<{}>,certType:<{}>,certNo:<{}>,signType:<{}>,signInst:<{}>", instId, modifyPayPasswdRequest.getCustAuthInfo().getCertType(), modifyPayPasswdRequest.getCustAuthInfo().getCertNo(), signType, signInst);
                        throw new BizException(RespCodeEnum.INVALID_SIGN.getRespCode(), RespCodeEnum.INVALID_SIGN.getRespDesc());
                    }
                    //校验当前用户，当前卡号签约关系是否存在
                    signAcctInfos = signAcctInfos.stream().filter(item -> userId.equals(item.getUserId())
                            && AppParamConstant.YES.equals(item.getSignStatus())
                            && modifyPayPasswdRequest.getCustAuthInfo().getPayAcctNo().equals(item.getSignAcctNo())).collect(Collectors.toList());
                    if (signAcctInfos.isEmpty()) {
                        rglog.info("签约关系不存在，instId:<{}>,certType:<{}>,certNo:<{}>,signType:<{}>,signInst:<{}>,userId:<{}>,signAcctNo:<{}>",
                                instId, modifyPayPasswdRequest.getCustAuthInfo().getCertType(), modifyPayPasswdRequest.getCustAuthInfo().getCertNo(), signType, signInst, userId, modifyPayPasswdRequest.getCustAuthInfo().getPayAcctNo());
                        throw new BizException(RespCodeEnum.INVALID_SIGN.getRespCode(), RespCodeEnum.INVALID_SIGN.getRespDesc());
                    }
                    //校验用户的证件类型是否一致
                    List<SignAcctInfo> signAcctInfoList = signAcctInfos.stream().filter(item -> modifyPayPasswdRequest.getCustAuthInfo().getCertType().equals(item.getCertType())).collect(Collectors.toList());
                    if (signAcctInfoList.isEmpty()) {
                        rglog.warn("用户未使用当前证件类型做签约交易,certType:<{}>,userId:<{}>", modifyPayPasswdRequest.getCustAuthInfo().getCertType(), userId);
                        throw new BizException(RespCodeEnum.GET_SIGN_INFO_ERROR.getRespCode(), RespCodeEnum.GET_SIGN_INFO_ERROR.getRespDesc());
                    }
                    for (SignAcctInfo signAcctInfo : signAcctInfoList) {
                        if (!modifyPayPasswdRequest.getCustAuthInfo().getCertNo().equals(signAcctInfo.getCertNo())) {
                            rglog.info("证件类型一致但证件号不一致，certType:<{}>,上传证件号:<{}>,已签约存在的证件号:<{}>", modifyPayPasswdRequest.getCustAuthInfo().getCertType(), modifyPayPasswdRequest.getCustAuthInfo().getCertNo(), signAcctInfo.getCertNo());
                            throw new BizException(RespCodeEnum.CERT_NO_DIFF.getRespCode(), RespCodeEnum.CERT_NO_DIFF.getRespDesc());
                        }
                    }
                    break;
                }
                default: {
                    rglog.info("认证方式错误");
                    throw new BizException(RespCodeEnum.USER_INFO_MISMATCH.getRespCode(), RespCodeEnum.USER_INFO_MISMATCH.getRespDesc());
                }
            }
            //身份验证通过后，需要把认证token存在会话的缓存数据中，并返回token
            rglog.debug("身份认证成功,设置认证token");
            String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
            userService.setUserSessionValue(UserSessionConstant.IDENTITY_VERIFY_SEQ_NUM, sysSeqNum);
            //身份验证通过后，将系统流水号作为认证token返回
            modifyPayPasswdResponse.setAuthToken(sysSeqNum);
            bizResponse.setResult(modifyPayPasswdResponse);
            bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            return bizResponse;
        }
        //交易类别 01-支付密码修改
        else if ("01".equals(txnMode)) {
            //查询非金融交易流水表（T_P_NON_FINANCE_TXN）获取身份验证交易结果状态
            rglog.debug("验证码验证流水号：<{}>", modifyPayPasswdRequest.getAuthToken());
            NonFinanceTxnMapper nonFinanceTxnMapper = new NonFinanceTxnMapperImpl();
            NonFinanceTxn nonFinanceTxn = nonFinanceTxnMapper.selectNonFinanceTxnInfoByPrimaryKey(instId, modifyPayPasswdRequest.getAuthToken());
            if (nonFinanceTxn == null) {
                rglog.info("非金融流水表中无该请求短信验证码交易，instId:<{}>,transSeqNum:<{}>", instId, modifyPayPasswdRequest.getAuthToken());
                throw new BizException(RespCodeEnum.VERIFICATION_CODE_INVALID.getRespCode(), RespCodeEnum.VERIFICATION_CODE_INVALID.getRespDesc());
            }
            //状态为“1”（交易成功）时，校验通过,否则，应答“身份验证失败”
            if (!TransStatusEnum.TRANS_SUCC.getStatus().equals(nonFinanceTxn.getTxnStatus())) {
                rglog.info("身份验证失败!");
                throw new BizException(RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespCode(), RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespDesc());
            }
            //校验验证码流水号字段，根据session获取会话对象数据，从session对象获取authToken无缓存数据则验证失败；有缓存数据验证通过。验证通过后，设置value为空
            String authTokenValue = userService.getUserSessionValue(UserSessionConstant.IDENTITY_VERIFY_SEQ_NUM);
            if (StringUtil.isEmptyOrNull(authTokenValue) || !authTokenValue.equals(modifyPayPasswdRequest.getAuthToken())) {
                rglog.info("从session对象获取authToken数据失败!");
                throw new BizException(RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespCode(), RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespDesc());
            }
            //修改成功后更新修改短信验证码的存储信息为空
            rglog.debug("authToken认证成功，重置authToken为空");
            userService.setUserSessionValue(UserSessionConstant.IDENTITY_VERIFY_SEQ_NUM, null);
            //设置用户支付密码（password) 区分移动收银台和WEB收银台
            String passwordOffset;
            SafeKeyBoardService safeKeyBoardService = new SafeKeyBoardServiceImpl();
            PasswordInfo passwordInfo = new PasswordInfo(userInfo.getTransPasswordSalt(), PinTypeEnum.DIGITAL, modifyPayPasswdRequest.getPassword());
            rglog.info("<{}>发起的设置支付密码...", modifyPayPasswdRequest.getHeader().getChanlId());
            passwordOffset = safeKeyBoardService.encryptPassword(instId, null, passwordInfo, null);
            if (null == passwordOffset) {
                rglog.error("设置用户支付密码失败!");
                throw new BizException(RespCodeEnum.USER_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespDesc());
            }
            userInfo.setTransPassword(passwordOffset);
            userInfo.setTransPasswordErrorTimes(0);
            //更新用户支付密码（TRANS_PASSWORD)
            boolean modifyFlag = userService.updateUserInfo(userInfo);
            if (!modifyFlag) {
                rglog.info("更新收银台用户信息表用户支付密码失败，instId:<{}>,userId<{}>", instId, userId);
                throw new BizException(RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespDesc());
            }
            rglog.debug("更新收银台用户信息表用户支付密码成功，instId:<{}>,userId<{}>", instId, userId);
            //响应
            bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            return bizResponse;
        } else {
            rglog.warn("请求参数上送错误，无法识别的交易类别。txnMode:<{}>", txnMode);
            throw new BizException(RespCodeEnum.PARAM_ERROR.getRespCode(), RespCodeEnum.PARAM_ERROR.getRespDesc());
        }
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        ModifyPayPasswdResponse modifyPayPasswdResponse = (ModifyPayPasswdResponse) bizResponse.getResult();
        ConvertUtil.convertInput(modifyPayPasswdResponse);
    }
}
